//------------------------------------------------------------------------------
//  <copyright file="ImageMatcher.h" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//  </copyright>
//------------------------------------------------------------------------------
#include <vtcommon.h>
#include <vtnumerics.h>
#include <vtcore.h>
#include <vt_io.h>
#include "vtimgproc.h"
#include <vt_edgedetect.h>
#include <vt_linedetector.h>
#include "VisionTools/ImageEdgel.h"
#include "VisionTools/ImageEllipse.h"
#include "VisionTools/ImageLine.h"
#include "ImageFrame.h"
#include "ImageOperations2DInterop.h"
#include <sunflower.h>

namespace Microsoft 
{
    namespace Robotics 
    {
        namespace Vision 
        {
			/// <summary>
			/// Struct that contains data about a feature
			/// For complete documentation view 30 of the sunflower documentation
			/// \external\MSRVision\Sunflower\Sunflower\doc\SunflowerDocumentation.docx
			/// </summary>
			public value struct Feature
{
				/// <summary>
				/// The X Position
				/// </summary>
				float X;		

				/// <summary>
				/// The Y Position
				/// </summary>
				float Y;

				/// <summary>
				/// The variance of the scale in the x direction
				/// </summary>
				float Sxx;

				/// <summary>
				/// The variance of the scale in the y direction
				/// </summary>
				float Syy;		

				/// <summary>
				/// The variance of the scale in the $xy$ direction
				/// </summary>
				float Sxy;		

				/// <summary>
				/// Score of the feature, higher is "better", no documentation on what is a "high" number.
				/// </summary>
				float Score;
			};

			/// <summary>
			/// Struct that contains data about two matched features
			/// </summary>
			public value struct MatchedFeatures
			{
				/// <summary>
				/// The index of the most likely image
				/// </summary>
				int MostLikelyImage;

				/// <summary>
				/// The index of the feature in the query image
				/// </summary>
				int QueryImageFeatureId;

				/// <summary>
				/// The index of the feaure in the matched image.
				/// </summary>
				int DatabaseFeatureId;
			};

			/// <summary>
			/// Class that builds up a KD tree from descriptors found in images
			/// And can be queried to find the most likely image from an input image
			/// </summary>
			public ref class ImageMatcher
			{
			public:
				/// <summary>
				/// Initializes a new instance of the ImageMatcher class
				/// </summary>
				/// <param name="featureCount">The maximum number of features to find</param>
				/// <param name="threshold">The ratio between two points for them to be considered matched.  0 = Perfect match, 1 = Match with anything, suggested = 0.5</param>
				/// <param name="detector">The type of feature to detect, use values in SunflowerConstants.cs</param>
				/// <param name="culling">The type of culling to use, use values in SunflowerConstants.cs</param>
				ImageMatcher(int featureCount, float ratio, int detector, int culling);

				/// <summary>
				/// Adds an image to the KD tree loaded from a file
				/// </summary>
				/// <param name="filename">The name of the file to load</param>
				/// <returns>The number of features found</returns>
				int AddImage(String ^filename, array<Feature> ^features);

				/// <summary>
				/// Adds a grayscale image to the KD tree 
				/// </summary>
				/// <param name="grayImage">The grayscale image to add</param>
				/// <param name="width">width of the image</param>
				/// <param name="height">height of the image</param>
				/// <param name="stride">stride, in bytes, of one row of the image</param>
				/// <returns>The number of features found</returns>
				int AddImage(BYTE *grayImage, int width, int height, int stride, array<Feature> ^features);

				/// <summary>
				/// Matches an image loaded from a file
				/// </summary>
				/// <param name="filename">Name of the file to load</param>
				/// <param name="features">The features found in the query image</param>
				/// <param name="matchedFeatures">The matched features</param>
				/// <returns>The number of features found in the input image</returns>
				int MatchImage(String ^filename, array<Feature> ^features, array<MatchedFeatures> ^matchedFeatures);

				/// <summary>
				/// Matches an image
				/// </summary>
				/// <param name="grayImage">The grayscale image to add</param>
				/// <param name="width">width of the image</param>
				/// <param name="height">height of the image</param>
				/// <param name="stride">stride, in bytes, of one row of the image</param>
				/// <param name="features">The features found in the query image</param>
				/// <param name="matchedFeatures">The matched features</param>
				/// <returns>The number of features found in the input image</returns>
				int MatchImage(BYTE *grayImage, int width, int height, int stride, array<Feature> ^features, array<MatchedFeatures> ^matchedFeatures);

				/// <summary>
				/// Gets the index of the matched image
				/// The index is generated in the order in which images are added.
				/// </summary>
				/// <returns>The index of the matched image</returns>
				int MatchedImage()
				{
					return this->mostLikelyImage;
				}

			private:
				/// <summary>
				/// The matcher that builds up the KD tree and finds a match from an input image
				/// using Sunflower descriptors
				/// </summary>
				ISimpleMatcher *pMatcher;

				/// <summary>
				/// The number of images in the database
				/// </summary>
				int numImages;

				/// <summary>
				/// The index of the most likely image
				/// </summary>
				int mostLikelyImage;
			};
		}
	}
}
